#include "include/ucwebimagejpeg2webp.h"

int write_data(const uint8_t* data, size_t data_size,
               const WebPPicture* picture)
{
  string *p = (string*)(picture->custom_ptr);
  if (p)
    (*p).append((char*)data, data_size);
  return 1;
}



ucwebImageJpeg2Webp::ucwebImageJpeg2Webp()
  /*  :ucwebImage() */
{

}

ucwebImageJpeg2Webp::ucwebImageJpeg2Webp(const char *filename, int quality, float percentage_resize, const char *outfilename)
  :/*ucwebImage(),*/filename(filename), quality_image(quality), percentage_resize(percentage_resize), 
   blob(NULL), image(NULL), output(NULL), done_webpimage_info(0), ok(-1)
{
  //sprintf(outfile, "output%d", file_no);
  //strcpy(outfile, outfilename);
  sprintf(outfile, "../changed/%s", outfilename);
}

ucwebImageJpeg2Webp::~ucwebImageJpeg2Webp()
{
  if (ok == 0) {
    WebPPictureFree(&picture);
  }
  if(blob) {
    delete blob;
  }

  if (image) {
    delete image;
  }

  if (output) {
    delete output;
  }

}



int ucwebImageJpeg2Webp::DecompressByGm()
{
  try {
    // Read a file into image object
    image = new Magick::Image(filename);
    // Write the image to a file
    return 0;
  }catch( Exception &error_ )
  {
    cout << "Caught exception: " << error_.what() << endl;
    return -1;
  }
}

int ucwebImageJpeg2Webp::DecompressByJpeglib()
{
  FILE *in_file = fopen(filename.c_str(), "rb");
  if (in_file == NULL) {
    fprintf(stderr, "Error! Failed open the image file by jpeglib!\n");
    return -1;
  }
  int ok = -1;
 try { 
  struct jpeg_decompress_struct dinfo;

  JSAMPROW buffer[1];
  struct jpeg_error_mgr jerr;

  dinfo.err = jpeg_std_error(&jerr);

  jpeg_create_decompress(&dinfo);
  jpeg_stdio_src(&dinfo, in_file);
  jpeg_read_header(&dinfo, TRUE);

  dinfo.out_color_space = JCS_RGB;
  dinfo.do_fancy_upsampling = TRUE;
  //jpeg_calc_output_dimensions(&dinfo);
  jpeg_start_decompress(&dinfo);

  output = new jpeg_image_info_byjpegc;

  if (NULL == output) {
    fprintf(stderr, "Error! Cannot new memory for output infomation at %d in %s\n", __LINE__, __FILE__);
    goto End;
  }

  output->width = dinfo.output_width;
  output->height = dinfo.output_height;
  output->stride = dinfo.output_width * dinfo.output_components * sizeof(*(output->rgb));
  output->rgb = (uint8_t*)malloc(output->stride * output->height);
  if (output->rgb == NULL) {  
    goto End;
  }
  buffer[0] = (JSAMPLE*)(output->rgb);

  while (dinfo.output_scanline < dinfo.output_height) {
    if (jpeg_read_scanlines(&dinfo, buffer, 1) != 1) {
      goto End;
    }
    buffer[0] += output->stride;
  }

  jpeg_finish_decompress(&dinfo);
  jpeg_destroy_decompress(&dinfo);
  ok = 0;
  goto End;
  }catch( Exception &error_ )
  {
    cout << "Caught exception: " << error_.what() << endl;
    return -1;
  }

End:
  fclose(in_file);
  return ok;
}

int ucwebImageJpeg2Webp::ResizeByWebp()
{
  int resize_w = 0;
  int resize_h = 0;
  int ok = -1;
  // resize the picture in Libwebp.
  resize_w = (int)(picture.width * percentage_resize);
  resize_h = (int)(picture.height * percentage_resize);
  if ((resize_w | resize_h) > 0) {
    if (!WebPPictureRescale(&picture, resize_w, resize_h)) {
      fprintf(stderr, "Error! Cannot resize pictureat %d in %s\n", __LINE__, __FILE__);
     goto EndResizeByWebp;
    }
  }
  ok = 0;
  goto EndResizeByWebp;

EndResizeByWebp:
  return ok;
}

int ucwebImageJpeg2Webp::ResizeByGm()
{
  int ok = -1;
  if (NULL == image) {
    fprintf(stderr, "Error! The image is NULL at %d in %s\n", __LINE__, __FILE__);
    return ok;
  }
  
  int resize_w = (int)(image->columns() * percentage_resize);
  int resize_h = (int)(image->rows() * percentage_resize);
  Magick::Geometry geometry(resize_w, resize_h);
  geometry.aspect(true);
  image->scale(geometry);
  ok = 0;
  goto End;

End:
 return ok;
}

int ucwebImageJpeg2Webp::CompressByGm()
{
  image = new Image(output->width, output->height, "RGB", CharPixel, output->rgb);
  return 0;
}

int ucwebImageJpeg2Webp::CompressByWebp(bool resize)
{
  int ok  = -1;
  string newData;
/*
  if (ProduceWebpInfoFromJpeg() && ProduceWebpInfoFromGm()) {
    fprintf(stderr, "Error! Failed in ProduceWebpInofmation! at %d in %s\n", __LINE__, __FILE__);
    goto End;
  }
*/
  if (resize) {
    if (!ResizeByWebp()) {
      fprintf(stderr, "Error! Failed resize the image in libwenp! at %d in %s\n.", __LINE__, __FILE__);
      goto End;
    }
  }
  picture.writer = write_data;
  picture.custom_ptr = &newData;
  if (WebPEncode(&config, &picture)) {
    //aData.update(newData.c_str(), newData.length());
    ok = WriteResult(newData.c_str(), newData.length(), outfile);
  }
  goto End;

End:
  return ok;
}


int ucwebImageJpeg2Webp::InitWebp()
{
  bool flag = false;

  if (0 == ok) {
   goto End;
  }

  flag = WebPPictureInit(&picture) && WebPConfigInit(&config);
  if (!flag) {
    fprintf(stderr, "Error! Failed WebPPictureInit(&picture) && WebPConfigInit(&config) %d in %s\n", __LINE__, __FILE__);
    goto End;
  }
  ok = 0;
  goto End;

End:
  return ok;
}

int ucwebImageJpeg2Webp::ProduceWebpInfoFromJpeg()
{
  if(done_webpimage_info) {
    fprintf(stderr, "Error! The information of a webp image had been produced in ProduceWebpInfoFromGm()\n!");
    return 0;
  }
  int ok = -1;
  if (-1 == InitWebp()) {
    goto End;
  }

  if (NULL == output) {
    fprintf(stderr, "Error! The output is NULL at %d in %s\n", __LINE__, __FILE__);
    goto End;
  }

  picture.width = output->width;
  picture.height = output->height;
  config.quality = quality_image;

  if(WebPPictureImportRGB(&picture, output->rgb, output->stride)) {
    ok = 0;
    done_webpimage_info = 1;
  }
  goto End;

End:
  return ok;
}

int ucwebImageJpeg2Webp::ProduceWebpInfoFromGm()
{
  if(done_webpimage_info) {
    fprintf(stderr, "Error! The information of a webp image had been produced in ProduceWebpInfoFromJpeg()\n!");
    return 0;
  }
  int ok = -1;
  if (-1 == InitWebp()) {
    return -1;;
  }

  if (NULL == image) {
    fprintf(stderr, "Error! The image is NULL at %d in %s\n", __LINE__, __FILE__);
    return -1;
  }
  picture.width = image->columns();
  picture.height = image->rows();
  config.quality = quality_image;

  int width = image->columns();
  int height = image->rows();
  const Magick::PixelPacket *pixels =  (*image).getConstPixels(0, 0, width, height);
  if (WebPPictureImportBGRX(&picture, (uint8_t*)pixels, picture.width * sizeof(Magick::PixelPacket))){
    ok = 0;
    done_webpimage_info = 1;
  }
  goto End;

End:
  return ok;

}

int ucwebImageJpeg2Webp::ProduceGmInfoFromJpeg()
{
  image = new Image(output->width, output->height, "RGB", CharPixel, output->rgb);
  return 0;
}

int ucwebImageJpeg2Webp::WriteResult(const char* data, size_t data_size, const char *filename)
{
  try {
    FILE *f = fopen(filename, "wb");
    fwrite(data, 1, data_size, f);
    fclose(f);
    return 0;
  }catch( Exception &error_ )
  {
    cout << "Caught exception: " << error_.what() << endl;
    return -1;
  }
}

int ucwebImageJpeg2Webp::libjpegGMWebP()
{
  return 0;
}

int ucwebImageJpeg2Webp::DecomGmResizeGm()
{
  int ok = -1;
  if(DecompressByGm() == -1) {
    fprintf(stderr, "Error! Failed decompress the image file by GM library! at %d in %s.\n", __LINE__, __FILE__);
    goto End;
  }
  
  if (ResizeByGm() == -1) {
    fprintf(stderr, "Error! Failed resize a image file by GM! at %d in %s\n", __LINE__, __FILE__);
    goto End;
  }
  
  if(ProduceWebpInfoFromGm() == -1) {
    fprintf(stderr, "Error! Failed produce  the image data from  Image class (GM)! at %d in %s.\n", __LINE__, __FILE__);
    goto End;
  }
  
  if (CompressByWebp(false) == -1) {
    fprintf(stderr, "Error! Failed compress the image by Webp library at %d in %s.\n" __FILE__, __FILE__);
    goto End;
  }
  ok = 0;
  goto End;

End:
  return ok;

}

int ucwebImageJpeg2Webp::DecomGmResizeWebp()
{
  int ok = -1;
  if(DecompressByGm() == -1) {
    fprintf(stderr, "Error! Failed decompress the image file by GM library! at %d in %s.\n", __LINE__, __FILE__);
    goto End;
  }
  
  if(ProduceWebpInfoFromGm() == -1) {
    fprintf(stderr, "Error! Failed produce  the image data from  Image class (GM)! at %d in %s.\n", __LINE__, __FILE__);
    goto End;
  }
  
  if (ResizeByWebp() == -1) {
    fprintf(stderr, "Error! Failed resize a image file by Webp library! at %d in %s\n", __LINE__, __FILE__);
    goto End;
  }
  
  if (CompressByWebp(false) == -1) {
    fprintf(stderr, "Error! Failed compress the image by Webp library at %d in %s.\n" __FILE__, __FILE__);
    goto End;
  }
  ok = 0;
  goto End;

End:
  return ok;
}

int ucwebImageJpeg2Webp::DecomJpegResizeGm()
{
  int ok = -1;
  if(DecompressByJpeglib() == -1) {
    fprintf(stderr, "Error! Failed decompress the image file by GM library! at %d in %s.\n", __LINE__, __FILE__);
    goto End;
  }
  
  if(ProduceGmInfoFromJpeg() == -1) {
    fprintf(stderr, "Error! Failed produce  the image data from Jpeg out information! at %d in %s.\n", __LINE__, __FILE__);
    goto End;
  }

  if (ResizeByGm() == -1) {
    fprintf(stderr, "Error! Failed resize a image file by GM! at %d in %s\n", __LINE__, __FILE__);
    goto End;
  }
  
  if(ProduceWebpInfoFromGm() == -1) {
    fprintf(stderr, "Error! Failed produce  the image data from  Image class (GM)! at %d in %s.\n", __LINE__, __FILE__);
    goto End;
  }
  
  if (CompressByWebp(false) == -1) {
    fprintf(stderr, "Error! Failed compress the image by Webp library at %d in %s.\n" __FILE__, __FILE__);
    goto End;
  }
  ok = 0;
  goto End;

End:
  return ok;
}

int ucwebImageJpeg2Webp::DecomJpegResizeWebp()
{
  int ok = -1;
  if(DecompressByJpeglib() == -1) {
    fprintf(stderr, "Error! Failed decompress the image file by jpeg library! at %d in %s.\n", __LINE__, __FILE__);
    goto End;
  }
  if(ProduceWebpInfoFromJpeg() == -1) {
    fprintf(stderr, "Error! Failed produce  the image data from jpeg out information! at %d in %s.\n", __LINE__, __FILE__);
    goto End;
  }
  
  if (ResizeByWebp() == -1) {
    fprintf(stderr, "Error! Failed resize a image file by Webp library! at %d in %s\n", __LINE__, __FILE__);
    goto End;
  }
  
  if (CompressByWebp(false) == -1) {
    fprintf(stderr, "Error! Failed compress the image by Webp library at %d in %s.\n" __FILE__, __FILE__);
    goto End;
  }
  ok = 0;
  goto End;

End:
  return ok;

}



